//==============================================================================
//
// C++ Minimalistic-Control-Library for the Pappradio V 2.0
//
// Copyright (C) 2011  Stefan Fendt
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the  GNU Lesser General Public License  as published by the Free 
// Software Foundation;  either version 2.1 of the License,  or (at your option) 
// any later version.
//
// This library is distributed  in the hope that it will be useful,  but WITHOUT 
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
// details.
//
// You  should have  received  a copy  of the  GNU Lesser General Public License 
// along with this library; if not, write to the Free Software Foundation, Inc., 
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// =============================================================================

#ifndef __LIBPAPPRADIO_HPP__
#define __LIBPAPPRADIO_HPP__

// =============================================================================
// We maybe need some standard-headers, so we include them here...
// =============================================================================

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>

// =============================================================================
// There is a rather large data-"word" we need to manage. by using this union
// instead of just a bunch of chars/bytes, it should be easier to read the code
// and it should be easier to manipulate the right positions in it...
// =============================================================================

typedef union 
{
    unsigned char byte[32];         // access the data in the dataword either by
                                    // using the byte-index or, ...
    struct
    {
                                    // access the data by more intuitive names:
                                    //
        unsigned char icsWord[17];  // Index 0...16 Programming-word for the 
                                    //              ICS 307-03 PLL-clock-chip
                                    //              this data is filled in via
                                    //              the fqdata.dat frequencies-
                                    //              table.
                                    //
        unsigned char freqChange;   // Index 17     Set this to 1 for changing
                                    //              the frequency of the ICS.
                                    //              If set to 0 then only the
                                    //              filter and attenuator is
                                    //              set to a new value.
                                    //
        unsigned char activePLL;    // Index 18     Set this to 0 for using the
                                    //              ICS 307-03 PLL-clock-chip.
                                    //              It is planned that (if ever)
                                    //              there will be a version (or
                                    //              an additional upgrade-board)
                                    //              using an SI570 DSS-clock. If
                                    //              so, set this to 1 for using
                                    //              the SI570 instead of the 
                                    //              ICS. But currently this 
                                    //              has to be set to zero...
                                    //
        unsigned char clockOut;     // Index 19     This value has to be set
                                    //              depending on the series of
                                    //              the pappradio. For preSeries
                                    //              pappradios this has to be
                                    //              set to zero for all others
                                    //              it has to be set to 1.
                                    //
        unsigned char bitBP0;       // Index 20     Addressline for bandpass-
                                    //              filter. Either 0 or 1.
                                    //
        unsigned char bitBP1;       // Index 21     Addressline for bandpass-
                                    //              filter. Either 0 or 1.
                                    //
        unsigned char bitBP2;       // Index 22     Addressline for bandpass-
                                    //              filter. Either 0 or 1.
                                    //
        unsigned char bitAT0;       // Index 23     Addressline for attenuator.
                                    //              Set to either 0 or 1.
                                    //
        unsigned char bitAT1;       // Index 24     Addressline for attenuator.
                                    //              Set to either 0 or 1.
                                    //
        unsigned char _ICS_SYSCLK_; // Index 25     RESERVED! DO NOT TOUCH! THIS
                                    //              MAY DAMAGE THE RADIO! (Even
                                    //              if it did not happen until.)
                                    //              Always set to 0!
                                    //
        unsigned char _ICS_CS_;     // Index 26     RESERVED! DO NOT TOUCH! THIS
                                    //              MAY DAMAGE THE RADIO! (Even
                                    //              if it did not happen until.)
                                    //              Always set to 0!
                                    //
        unsigned char _ICS_DATA_;   // Index 27     RESERVED! DO NOT TOUCH! THIS
                                    //              MAY DAMAGE THE RADIO! (Even
                                    //              if it did not happen until.)
                                    //              Always set to 0!
                                    //
        unsigned char _ICS_DEBUG_;  // Index 28     RESERVED! DO NOT TOUCH! THIS
                                    //              MAY DAMAGE THE RADIO! (Even
                                    //              if it did not happen until.)
                                    //              Always set to 0!
                                    //
        unsigned char _PRG_FW_BIT_; // Index 29     Boot Bit für Umschaltung in
                                    //              Firmware Programmier-Modus.
                                    //              DO NOT TOUCH! SET TO 0!
                                    //
        unsigned char bitCHK0;      // Index 30     Check-Bit, Set to 0.
                                    //
        unsigned char bitCHK1;      // Index 31     Check-Bit, Set to 1.
                                    //
    };
} dataword_t;

// =============================================================================
// fqdata-entry: despite that dataword from above, we need to manage some raw-
//               ICS-307-03 programming-words for the frequencies we want to be
//               able to use. Having a typedef for this makes things a little
//               bit easier, too...
// =============================================================================

typedef struct
{
    unsigned char byte[17];
} icsword_t;

// =============================================================================
// So here the fun-stuff begins ... Let's get the radio do, what we want it to.
// =============================================================================

class Pappradio
{
    public:
    // ------------------------------------------------------------------------
    // some error-codes, so we know what happend...
    // ------------------------------------------------------------------------
    
    enum ERRORS
    {
        ERR_NONE,
        ERR_INIT_FQDATA,
        ERR_NOT_FOUND,
        ERR_PRODUCT_MISMATCH
    } ERRORS;
    
    // ------------------------------------------------------------------------
    // some names for the filters
    // ------------------------------------------------------------------------
    
    enum FILTERS
    {
        NO_FILTER,                  // no bandpass used at all
        BP_02400_04000,             //  2.4 MHz -  4.0 MHz
        BP_04000_07500,             //  4.0 MHz -  7.5 MHz
        BP_07500_14000,             //  7.5 MHz - 14.0 MHz
        BP_14000_30000,             // 14.0 MHz - 30.0 MHz
        EXT_1,                      // Extra filter 1 (not connected)
        EXT_2,                      // Extra filter 2 (not connected)
        EXT_3                       // Extra filter 3 (not connected)
    };
    
    // ------------------------------------------------------------------------
    // some names for the attenuators
    // ------------------------------------------------------------------------
    
    enum ATTENUATORS
    {
        ATT00,                      // no attenuation
        ATT10,                      // -10 dB
        ATT20,                      // -20 dB
        ATT30                       // -30 dB
    };
    
    // ------------------------------------------------------------------------
    // default constructor
    // ------------------------------------------------------------------------
    
                        Pappradio       ();
                    
    // ------------------------------------------------------------------------
    // default constructor
    // ------------------------------------------------------------------------
    
                       ~Pappradio       ();
   
    // ------------------------------------------------------------------------
    // try to find/detect and open the pappradio for communication
    // ------------------------------------------------------------------------
    
    enum ERRORS         open            ();
    
    // ------------------------------------------------------------------------
    // close communication with pappradio
    // ------------------------------------------------------------------------
    
    void                close           ();
    
    // ------------------------------------------------------------------------
    // just for convenience: check if opened successfully the other way...
    // ------------------------------------------------------------------------
    
    bool                isOpen          ();
    
    // ------------------------------------------------------------------------
    // load fqdata-table
    // 
    // Attention: You *HAVE* to do this before trying to open the radio! If you
    //            try to do this in reverse... expect to get some trouble.. ;-)
    // ------------------------------------------------------------------------
    
    bool                loadFQData      ( std::string filename );
    
    // ------------------------------------------------------------------------
    // Set the desired LO-fequency 
    // 
    // Input value is in Hz! The range is limited from 0Hz to 30MHz. This will
    // choose the closest match for this frequency from the fqdata. So you will
    // almost never get the desired frequency exactly. For reception on 3rd or
    // 5th harmonic calculate the mirror-frequency by yourself, set the filter
    // accordingly...
    // ------------------------------------------------------------------------

    void                setFrequency    ( double frequency );
    
    // ------------------------------------------------------------------------
    // Get the actual LO-frequency back
    //
    // Value is in Hz and represents the actual value the ICS 307-03 is running
    // on. Range is inbetween 0 ... 30 MHz, so for harmonic reception you have
    // to correct the value by yourself!
    // ------------------------------------------------------------------------

    double              getFrequency    ();
    
    // ------------------------------------------------------------------------
    // Set the bandpassfilter
    // ------------------------------------------------------------------------

    void                setFilter       ( enum FILTERS filter );

    // ------------------------------------------------------------------------
    // Get back current bandpassfilter-setting
    // ------------------------------------------------------------------------

    enum FILTERS        getFilter       ();
    
    // ------------------------------------------------------------------------
    // Set the attenuator
    // ------------------------------------------------------------------------

    void                setAttenuator   ( enum ATTENUATORS attenuator );

    // ------------------------------------------------------------------------
    // Get back current attenuator-setting
    // ------------------------------------------------------------------------

    enum ATTENUATORS    getAttenuator   ();
    
    // ------------------------------------------------------------------------
    // everything below is *** PRIVATE ***
    // ------------------------------------------------------------------------
    
    private:
    
    // ------------------------------------------------------------------------
    // prepare and send the dataword
    // ------------------------------------------------------------------------
    
    bool            sendData( bool freqChange );
    
    // ------------------------------------------------------------------------
    // just a simple way to get a bit out of the ICS-Programming-Word
    // ------------------------------------------------------------------------

    bool            getBitInProgWord( unsigned int bitNumber, 
                                      unsigned char progWord[17] );
                                      
    // the USB-Product- and USB-Vendor-Codes of the pappradio V2
    
    int const static    m_USBVendorID  = 0x03eb;
    int const static    m_USBProductID = 0x2014;
    
    // the dataword we need to send to the pappradio
    
    dataword_t          m_Dataword;
    
    // the settings of the pappradio
    
    double              m_TargetFrequency;
    double              m_RealFrequency;
    
    enum ATTENUATORS    m_Attenuator;
    enum FILTERS        m_Filter;
    
    bool                m_FQDataAvailable;
    icsword_t           m_FQData[30000]; // 0...30MHz in 1kHz steps ...
    
    // some variables/structures we need for communication
    
//    struct libusb_device_handle* m_DeviceHandle;
    void*                  m_DeviceHandle;
    bool                         m_DeviceReady;
    
};

#endif

